/*
 * Created on 16 juin 2003
 * Copyright (C) Azureus Software, Inc, All Rights Reserved.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 *
 */
package org.gudy.azureus2.core3.util;

import java.io.InputStreamReader;
import java.io.LineNumberReader;
import java.nio.charset.Charset;
import java.security.AccessControlException;
import java.util.Locale;
import java.util.StringTokenizer;
import java.util.TimeZone;
import java.util.regex.Pattern;

/**
 * 
 * @author Olivier
 * 
 */

public class Constants {
    public static final String EMPTY_STRING = "";
    public static final String SF_WEB_SITE = "http://plugins.vuze.com/";

    public static final String AELITIS_TORRENTS = "http://cf1.vuze.com/torrent/torrents/";
    public static final String AELITIS_FILES = "http://cf1.vuze.com/torrent/files/";
    public static final String AZUREUS_WIKI = "http://wiki.vuze.com/w/";

    public static final String VERSION_SERVER_V4 = "version.vuze.com";
    public static final String VERSION_SERVER_V6 = "version6.vuze.com";

    public static final String DHT_SEED_ADDRESS_V4 = "dht.vuze.com";
    public static final String DHT_SEED_ADDRESS_V6 = "dht6.vuze.com";
    public static final String DHT_SEED_ADDRESS_V6_TUNNEL = "dht6tunnel.vuze.com";

    public static final String NAT_TEST_SERVER = "nettest.vuze.com";
    public static final String NAT_TEST_SERVER_HTTP = "http://nettest.vuze.com/";

    public static final String SPEED_TEST_SERVER = "speedtest.vuze.com";

    public static final String PAIRING_URL = "https://pair.vuze.com/pairing";

    public static final String[] AZUREUS_DOMAINS = { "azureusplatform.com", "azureus.com", "aelitis.com", "vuze.com" };

    public static final String DEFAULT_ENCODING = "UTF8";
    public static final String BYTE_ENCODING = "ISO-8859-1";
    public static final Charset BYTE_CHARSET;
    public static final Charset DEFAULT_CHARSET;

    public static final int DEFAULT_INSTANCE_PORT = 6880;
    public static final int INSTANCE_PORT;

    static {
        String ip_str = System.getProperty("azureus.instance.port", String.valueOf(DEFAULT_INSTANCE_PORT));

        int ip;
        try {
            ip = Integer.parseInt(ip_str);
        } catch (Throwable e) {
            ip = DEFAULT_INSTANCE_PORT;
        }

        INSTANCE_PORT = ip;

        Charset bc = null;
        Charset dc = null;

        try {
            bc = Charset.forName(Constants.BYTE_ENCODING);
            dc = Charset.forName(Constants.DEFAULT_ENCODING);

        } catch (Throwable e) {

            e.printStackTrace();
        }

        BYTE_CHARSET = bc;
        DEFAULT_CHARSET = dc;
    }

    public static final Locale LOCALE_ENGLISH = new Locale("en", "");

    static {
        try {
            String timezone = System.getProperty("azureus.timezone", null);

            if (timezone != null) {

                TimeZone.setDefault(TimeZone.getTimeZone(timezone));
            }
        } catch (Throwable e) {

            // can happen in applet

            if (e instanceof AccessControlException) {

            } else {

                e.printStackTrace();
            }
        }
    }

    public static final String INFINITY_STRING = "\u221E"; // "oo";pa
    public static final int CRAPPY_INFINITY_AS_INT = 365 * 24 * 3600; // seconds (365days)
    public static final long CRAPPY_INFINITE_AS_LONG = 10000 * 365 * 24 * 3600; // seconds (10k years)

    public static boolean DOWNLOAD_SOURCES_PRETEND_COMPLETE = false;

    // keep the CVS style constant coz version checkers depend on it!
    // e.g. 2.0.8.3
    // 2.0.8.3_CVS
    // 2.0.8.3_Bnn // incremental build

    public static String APP_NAME = "Vuze";
    public static final String AZUREUS_NAME = "Azureus";
    public static final String AZUREUS_PROTOCOL_NAME_PRE_4813 = "Azureus";
    public static final String AZUREUS_PROTOCOL_NAME = "Vuze";
    public static final String AZUREUS_VERSION = "5.5.0.0";
    public static final String BUILD_VERSION = "@build.version@"; // Ant replace
    public static final String AZUREUS_SUBVER = "";
    public static final byte[] VERSION_ID = ("-" + "AZ" + "5500" + "-").getBytes(); // MUST be 8 chars long!

    private static final boolean FORCE_NON_CVS = System.getProperty("az.force.noncvs", "0").equals("1");

    public static final boolean IS_CVS_VERSION = isCVSVersion(AZUREUS_VERSION) && !FORCE_NON_CVS;

    public static final String OSName = System.getProperty("os.name");

    public static final boolean isOSX = OSName.toLowerCase().startsWith("mac os");
    public static final boolean isLinux = OSName.equalsIgnoreCase("Linux");
    public static final boolean isSolaris = OSName.equalsIgnoreCase("SunOS");
    public static final boolean isFreeBSD = OSName.equalsIgnoreCase("FreeBSD");
    public static final boolean isWindowsXP = OSName.equalsIgnoreCase("Windows XP");
    public static final boolean isWindows95 = OSName.equalsIgnoreCase("Windows 95");
    public static final boolean isWindows98 = OSName.equalsIgnoreCase("Windows 98");
    public static final boolean isWindows2000 = OSName.equalsIgnoreCase("Windows 2000");
    public static final boolean isWindowsME = OSName.equalsIgnoreCase("Windows ME");
    public static final boolean isWindows9598ME = isWindows95 || isWindows98 || isWindowsME;

    public static boolean isSafeMode = false;

    public static final boolean isWindows = OSName.toLowerCase().startsWith("windows");
    // If it isn't windows or osx, it's most likely an unix flavor
    public static final boolean isUnix = !isWindows && !isOSX;

    public static final boolean isWindowsVista;
    public static final boolean isWindowsVistaSP2OrHigher;
    public static final boolean isWindowsVistaOrHigher;
    public static final boolean isWindows7OrHigher;
    public static final boolean isWindows8OrHigher;

    // Common Patterns
    public static final Pattern PAT_SPLIT_COMMAWORDS = Pattern.compile("\\s*,\\s*");
    public static final Pattern PAT_SPLIT_COMMA = Pattern.compile(",");
    public static final Pattern PAT_SPLIT_DOT = Pattern.compile("\\.");
    public static final Pattern PAT_SPLIT_SPACE = Pattern.compile(" ");
    public static final Pattern PAT_SPLIT_SLASH_N = Pattern.compile("\n");

    public static final boolean is64Bit;

    static {
        boolean _is64Bit;

        try {
            _is64Bit = System.getProperty("os.arch").contains("64");

        } catch (Throwable e) {

            _is64Bit = false;
        }

        is64Bit = _is64Bit;

        if (isWindows) {

            Float ver = null;

            try {
                ver = new Float(System.getProperty("os.version"));

            } catch (Throwable e) {
            }

            boolean vista_sp2_or_higher = false;

            if (ver == null) {

                isWindowsVista = false;
                isWindowsVistaOrHigher = false;
                isWindows7OrHigher = false;
                isWindows8OrHigher = false;

            } else {
                float f_ver = ver.floatValue();

                isWindowsVista = f_ver == 6;
                isWindowsVistaOrHigher = f_ver >= 6;
                isWindows7OrHigher = f_ver >= 6.1f;
                isWindows8OrHigher = f_ver >= 6.2f;

                if (isWindowsVista) {

                    LineNumberReader lnr = null;

                    try {
                        Process p =
                                Runtime.getRuntime()
                                        .exec(new String[] { "reg", "query", "HKLM\\Software\\Microsoft\\Windows NT\\CurrentVersion", "/v",
                                                "CSDVersion" });

                        lnr = new LineNumberReader(new InputStreamReader(p.getInputStream()));

                        while (true) {

                            String line = lnr.readLine();

                            if (line == null) {

                                break;
                            }

                            if (line.matches(".*CSDVersion.*")) {

                                vista_sp2_or_higher = line.matches(".*Service Pack [2-9]");

                                break;
                            }
                        }
                    } catch (Throwable e) {

                    } finally {

                        if (lnr != null) {

                            try {
                                lnr.close();

                            } catch (Throwable e) {
                            }
                        }
                    }
                }
            }

            isWindowsVistaSP2OrHigher = vista_sp2_or_higher;
        } else {

            isWindowsVista = false;
            isWindowsVistaSP2OrHigher = false;
            isWindowsVistaOrHigher = false;
            isWindows7OrHigher = false;
            isWindows8OrHigher = false;
        }
    }

    public static final boolean isOSX_10_5_OrHigher;
    public static final boolean isOSX_10_6_OrHigher;
    public static final boolean isOSX_10_7_OrHigher;
    public static final boolean isOSX_10_8_OrHigher;

    static {
        if (isOSX) {

            int first_digit = 0;
            int second_digit = 0;

            try {
                String os_version = System.getProperty("os.version");

                String[] bits = os_version.split("\\.");

                first_digit = Integer.parseInt(bits[0]);

                if (bits.length > 1) {

                    second_digit = Integer.parseInt(bits[1]);
                }
            } catch (Throwable e) {

            }

            isOSX_10_5_OrHigher = first_digit > 10 || (first_digit == 10 && second_digit >= 5);
            isOSX_10_6_OrHigher = first_digit > 10 || (first_digit == 10 && second_digit >= 6);
            isOSX_10_7_OrHigher = first_digit > 10 || (first_digit == 10 && second_digit >= 7);
            isOSX_10_8_OrHigher = first_digit > 10 || (first_digit == 10 && second_digit >= 8);

        } else {

            isOSX_10_5_OrHigher = false;
            isOSX_10_6_OrHigher = false;
            isOSX_10_7_OrHigher = false;
            isOSX_10_8_OrHigher = false;
        }
    }

    public static final boolean isAndroid;

    static {
        String vm_name = System.getProperty("java.vm.name", "");

        isAndroid = vm_name.equalsIgnoreCase("Dalvik");
    }

    // Android is roughly 1.6 (reports as 0 for java.version)

    public static final String JAVA_VERSION;
    public static final int API_LEVEL;

    static {
        String java_version = isAndroid ? "1.6" : System.getProperty("java.version");
        int api_level = 0;

        if (isAndroid) {

            String sdk_int = System.getProperty("android.os.build.version.sdk_int", "0");

            try {
                api_level = Integer.parseInt(sdk_int);

                if (api_level > 0 && api_level <= 8) {

                    java_version = "1.5";
                }
            } catch (Throwable e) {
            }
        }

        JAVA_VERSION = java_version;
        API_LEVEL = api_level;
    }

    public static final boolean isJava7OrHigher;

    static {
        // http://www.oracle.com/technetwork/java/javase/versioning-naming-139433.html
        // should always start with n.n.

        // unless it is Android where it is always 0

        boolean _7plus;

        try {
            String[] bits = JAVA_VERSION.split("\\.");

            int first = Integer.parseInt(bits[0]);
            int second = Integer.parseInt(bits[1]);

            _7plus = first > 1 || second >= 7;

        } catch (Throwable e) {

            System.err.println("Unparsable Java version: " + JAVA_VERSION);

            e.printStackTrace();

            _7plus = false; // derp
        }

        isJava7OrHigher = _7plus;
    }

    public static final String FILE_WILDCARD = isWindows ? "*.*" : "*";

    // use this if you want to prevent the constant getting cached in separately built objects (e.g. plugins)

    public static String getCurrentVersion() {
        return (AZUREUS_VERSION);
    }

    /**
     * Gets the current version, or if a CVS version, the one on which it is based
     * 
     * @return
     */

    public static String getBaseVersion() {
        return (getBaseVersion(AZUREUS_VERSION));
    }

    public static String getBaseVersion(String version) {
        int p1 = version.indexOf("_"); // _CVS or _Bnn

        if (p1 == -1) {

            return (version);
        }

        return (version.substring(0, p1));
    }

    /**
     * is this a formal build or CVS/incremental
     * 
     * @return
     */

    public static boolean isCVSVersion() {
        return IS_CVS_VERSION;
    }

    public static boolean isCVSVersion(String version) {
        return (version.indexOf("_") != -1);
    }

    /**
     * For CVS builds this returns the incremental build number. For people running their own builds this returns -1
     * 
     * @return
     */

    public static int getIncrementalBuild() {
        return (getIncrementalBuild(AZUREUS_VERSION));
    }

    public static int getIncrementalBuild(String version) {
        if (!isCVSVersion(version)) {

            return (0);
        }

        int p1 = version.indexOf("_B");

        if (p1 == -1) {

            return (-1);
        }

        try {
            return (Integer.parseInt(version.substring(p1 + 2)));

        } catch (Throwable e) {

            System.out.println("can't parse version");

            return (-1);
        }
    }

    public static boolean isCurrentVersionLT(String version) {
        return (compareVersions(AZUREUS_VERSION, version) < 0);
    }

    public static boolean isCurrentVersionGE(String version) {
        return (compareVersions(AZUREUS_VERSION, version) >= 0);
    }

    /**
     * compare two version strings of form n.n.n.n (e.g. 1.2.3.4)
     * 
     * @param version_1
     * @param version_2
     * @return -ve -> version_1 lower, 0 = same, +ve -> version_1 higher
     */

    public static int compareVersions(String version_1, String version_2) {
        try {
            version_1 = version_1.replaceAll("_CVS", "_B100");
            version_2 = version_2.replaceAll("_CVS", "_B100");

            if (version_1.startsWith(".")) {
                version_1 = "0" + version_1;
            }
            if (version_2.startsWith(".")) {
                version_2 = "0" + version_2;
            }

            version_1 = version_1.replaceAll("[^0-9.]", ".");
            version_2 = version_2.replaceAll("[^0-9.]", ".");

            StringTokenizer tok1 = new StringTokenizer(version_1, ".");
            StringTokenizer tok2 = new StringTokenizer(version_2, ".");

            while (true) {
                if (tok1.hasMoreTokens() && tok2.hasMoreTokens()) {

                    int i1 = Integer.parseInt(tok1.nextToken());
                    int i2 = Integer.parseInt(tok2.nextToken());

                    if (i1 != i2) {

                        return (i1 - i2);
                    }
                } else if (tok1.hasMoreTokens()) {

                    int i1 = Integer.parseInt(tok1.nextToken());

                    if (i1 != 0) {

                        return (1);
                    }
                } else if (tok2.hasMoreTokens()) {

                    int i2 = Integer.parseInt(tok2.nextToken());

                    if (i2 != 0) {

                        return (-1);
                    }
                } else {
                    return (0);
                }
            }
        } catch (Throwable e) {

            e.printStackTrace();

            return (0);
        }
    }

    public static boolean isValidVersionFormat(String version) {
        if (version == null || version.length() == 0) {

            return (false);
        }

        for (int i = 0; i < version.length(); i++) {

            char c = version.charAt(i);

            if (!(Character.isDigit(c) || c == '.')) {

                return (false);
            }
        }

        if (version.startsWith(".") || version.endsWith(".") || version.indexOf("..") != -1) {

            return (false);
        }

        return (true);
    }

    public static boolean isAzureusDomain(String host) {
        host = host.toLowerCase();

        for (int i = 0; i < AZUREUS_DOMAINS.length; i++) {

            String domain = (String) AZUREUS_DOMAINS[i];

            if (domain.equals(host)) {

                return (true);
            }

            if (host.endsWith("." + domain)) {

                return (true);
            }
        }

        return (false);
    }

    public static void main(String[] args) {
        System.out.println(compareVersions("3.0.0.1", "3.0.0.0"));
        System.out.println(compareVersions("3.0.0.0_B1", "3.0.0.0"));
        System.out.println(compareVersions("3.0.0.0", "3.0.0.0_B1"));
        System.out.println(compareVersions("3.0.0.0_B1", "3.0.0.0_B4"));
        System.out.println(compareVersions("3.0.0.0..B1", "3.0.0.0_B4"));
    }
}
